package pers.jsan.litheopen.security.prover;

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import pers.jsan.litheopen.security.cache.CacheUserManager;
import pers.jsan.litheopen.security.exception.LitheAuthenticationException;
import pers.jsan.litheopen.security.filter.AuthenticationFilterChain;
import pers.jsan.litheopen.security.filter.LitheAuthenticationFilter;
import pers.jsan.litheopen.security.oauth.model.LitheAuthenticationToken;
import pers.jsan.litheopen.security.oauth.model.UserDetail;

import java.util.ArrayList;
import java.util.List;

public class AuthenticationManager {

    private String loginPath = "/login";
    private String loginPage = "/login.html";
    private String webPath;
    private long tokenExpires = 7200L;
    private List<LitheAuthenticationFilter> authenticationFilters = new ArrayList<>();
    private AuthenticationFilterChain authenticationFilterChain = new AuthenticationFilterChain();
    private AuthenticationProver authenticationProver;
    private CacheUserManager cacheUserManager;
    private String authorizePath = "/oauth/authorize";
    private List<LitheAuthenticationFilter> authorizeFilters = new ArrayList<>();
    private AuthenticationFilterChain authorizeFilterChain = new AuthenticationFilterChain();
    private String accessTokenPath = "/oauth/accessToken";
    private List<LitheAuthenticationFilter> clientFilters = new ArrayList<>();
    private AuthenticationFilterChain clientFilterChain = new AuthenticationFilterChain();
    private String userGetTokenPath = "/oauth/getToken";
    private List<LitheAuthenticationFilter> userGetTokenFilters = new ArrayList<>();
    private AuthenticationFilterChain userGetTokenFilterChain = new AuthenticationFilterChain();
    private String userInterceptPath = "/**";
    private String userExcludePath = "";
    private String clientInterceptPath = "";
    private String clientExcludePath = "";

    //用户认证、客户端认证、用户在线校验、客户端在线校验拦截功能启停，启用：false，停用：true
    private boolean userLoginDisable = false;
    private boolean clientLoginDisable = false;
    private boolean userOnlineDisable = false;
    private boolean clientOnlineDisable = false;

    public String getLoginPath() {
        return loginPath;
    }

    /**
     * 后端登录接口
     * @param loginPath 登录接口
     * @return AuthenticationManager
     */
    public AuthenticationManager setLoginPath(String loginPath) {
        this.loginPath = loginPath;
        return this;
    }

    public String getLoginPage() {
        return loginPage;
    }

    /**
     * 设置登录页面接口
     * @param loginPage 登录页面接口
     * @return AuthenticationManager
     */
    public AuthenticationManager setLoginPage(String loginPage) {
        this.loginPage = loginPage;
        return this;
    }

    public String getWebPath() {
        return webPath;
    }

    /**
     * 设置前端访问地址
     * @param webPath 前端访问地址
     * @return AuthenticationManager
     */
    public AuthenticationManager setWebPath(String webPath) {
        this.webPath = webPath;
        return this;
    }

    public long getTokenExpires() {
        return tokenExpires;
    }

    /**
     * 设置凭证有效时间
     * @param tokenExpires 有效时间（秒）
     */
    public void setTokenExpires(long tokenExpires) {
        this.tokenExpires = tokenExpires;
    }

    public List<LitheAuthenticationFilter> getAuthenticationFilters() {
        return authenticationFilters;
    }

    public void setAuthenticationFilters(List<LitheAuthenticationFilter> authenticationFilters) {
        this.authenticationFilters = authenticationFilters;
    }

    public AuthenticationFilterChain getAuthenticationFilterChain() throws CloneNotSupportedException {
        AuthenticationFilterChain filterChain = this.authenticationFilterChain.copy();
        filterChain.setFilters(getAuthenticationFilters().iterator());
        return filterChain;
    }

    public AuthenticationManager setAuthenticationFilterChain(AuthenticationFilterChain filterChain) {
        this.authenticationFilterChain = filterChain;
        return this;
    }

    public String getAuthorizePath() {
        return authorizePath;
    }

    public AuthenticationManager setAuthorizePath(String authorizePath) {
        this.authorizePath = authorizePath;
        return this;
    }

    /**
     * 添加过认证滤器
     * @param filter 过滤器
     * @return AuthenticationManager
     */
    public AuthenticationManager addAuthenticationFilter(LitheAuthenticationFilter filter) {
        this.authenticationFilters.add(filter);
        return this;
    }

    /**
     * 置顶添加认证过滤器
     * @param filter 过滤器
     * @return AuthenticationManager
     */
    public AuthenticationManager addAuthenticationFilterToFirst(LitheAuthenticationFilter filter) {
        this.authenticationFilters.add(0, filter);
        return this;
    }

    public AuthenticationProver getAuthenticationProver() {
        return authenticationProver;
    }

    /**
     * 设置用户校验器
     * @param authenticationProver 校验器
     * @return AuthenticationManager
     */
    public AuthenticationManager setAuthenticationProver(AuthenticationProver authenticationProver) {
        this.authenticationProver = authenticationProver;
        return this;
    }

    public List<LitheAuthenticationFilter> getAuthorizeFilters() {
        return authorizeFilters;
    }

    public void setAuthorizeFilters(List<LitheAuthenticationFilter> authorizeFilters) {
        this.authorizeFilters = authorizeFilters;
    }

    public AuthenticationFilterChain getAuthorizeFilterChain() throws CloneNotSupportedException {
        AuthenticationFilterChain filterChain = this.authorizeFilterChain.copy();
        filterChain.setFilters(getAuthorizeFilters().iterator());
        return filterChain;
    }

    /**
     * 添加授权校验过滤器
     * @param filter 过滤器
     * @return AuthenticationManager
     */
    public AuthenticationManager addAuthorizeFilter(LitheAuthenticationFilter filter) {
        this.authorizeFilters.add(filter);
        return this;
    }

    /**
     * 置顶添加授权校验过滤器
     * @param filter 过滤器
     * @return AuthenticationManager
     */
    public AuthenticationManager addAuthorizeFilterToFirst(LitheAuthenticationFilter filter) {
        this.authorizeFilters.add(0, filter);
        return this;
    }

    public AuthenticationManager setAuthorizeFilterChain(AuthenticationFilterChain authorizeFilterChain) {
        this.authorizeFilterChain = authorizeFilterChain;
        return this;
    }

    public String getAccessTokenPath() {
        return accessTokenPath;
    }

    public void setAccessTokenPath(String accessTokenPath) {
        this.accessTokenPath = accessTokenPath;
    }

    public List<LitheAuthenticationFilter> getClientFilters() {
        return clientFilters;
    }

    public void setClientFilters(List<LitheAuthenticationFilter> clientFilters) {
        this.clientFilters = clientFilters;
    }

    public AuthenticationFilterChain getClientFilterChain() throws CloneNotSupportedException {
        AuthenticationFilterChain filterChain = this.clientFilterChain.copy();
        filterChain.setFilters(getClientFilters().iterator());
        return filterChain;
    }

    public void setClientFilterChain(AuthenticationFilterChain clientFilterChain) {
        this.clientFilterChain = clientFilterChain;
    }

    /**
     * 添加客户端授权校验过滤器
     * @param filter 过滤器
     * @return AuthenticationManager
     */
    public AuthenticationManager addClientFilter(LitheAuthenticationFilter filter) {
        this.clientFilters.add(filter);
        return this;
    }

    /**
     * 置顶添加客户端授权校验过滤器
     * @param filter 过滤器
     * @return AuthenticationManager
     */
    public AuthenticationManager addClientFilterToFirst(LitheAuthenticationFilter filter) {
        this.clientFilters.add(0, filter);
        return this;
    }

    public String getUserGetTokenPath() {
        return userGetTokenPath;
    }

    public void setUserGetTokenPath(String userGetTokenPath) {
        this.userGetTokenPath = userGetTokenPath;
    }

    public List<LitheAuthenticationFilter> getUserGetTokenFilters() {
        return userGetTokenFilters;
    }

    public void setUserGetTokenFilters(List<LitheAuthenticationFilter> userGetTokenFilters) {
        this.userGetTokenFilters = userGetTokenFilters;
    }

    public AuthenticationFilterChain getUserGetTokenFilterChain() throws CloneNotSupportedException {
        AuthenticationFilterChain filterChain = this.userGetTokenFilterChain.copy();
        filterChain.setFilters(getUserGetTokenFilters().iterator());
        return filterChain;
    }

    public void setUserGetTokenFilterChain(AuthenticationFilterChain userGetTokenFilterChain) {
        this.userGetTokenFilterChain = userGetTokenFilterChain;
    }

    /**
     * 添加临时授权码获取token过滤器
     * @param filter 过滤器
     * @return AuthenticationManager
     */
    public AuthenticationManager addUserGetTokenFilter(LitheAuthenticationFilter filter) {
        this.userGetTokenFilters.add(filter);
        return this;
    }

    /**
     * 置顶添加临时授权码获取token过滤器
     * @param filter 过滤器
     * @return AuthenticationManager
     */
    public AuthenticationManager addUserGetTokenToFirst(LitheAuthenticationFilter filter) {
        this.userGetTokenFilters.add(0, filter);
        return this;
    }

    /**
     * 认证方法
     * @param litheAuthenticationToken 登录信息
     * @return LitheAuthenticationToken
     * @throws LitheAuthenticationException e
     */
    public LitheAuthenticationToken authenticate(LitheAuthenticationToken litheAuthenticationToken) throws LitheAuthenticationException {
        return this.authenticationProver.authenticate(litheAuthenticationToken);
    }

    public Object formatOauthUserMessage(UserDetail userDetail) {
        return this.authenticationProver.formatOauthUserMessage(userDetail);
    }

    public CacheUserManager getCacheUserManager() {
        return cacheUserManager;
    }

    /**
     * 设置用户信息缓存管理器
     * @param cacheUserManager 用户信息缓存管理器
     */
    public AuthenticationManager setCacheUserManager(CacheUserManager cacheUserManager) {
        this.cacheUserManager = cacheUserManager;
        return this;
    }

    /**
     * 缓存用户信息
     * @param litheAuthenticationToken 凭证与用户信息
     * @return String
     */
    public String cacheLitheAuthenticationToken(LitheAuthenticationToken litheAuthenticationToken) {
        //生成token
        String token = litheAuthenticationToken.getToken();
        cacheUserManager.cacheLitheAuthenticationToken(token, litheAuthenticationToken, tokenExpires);
        return token;
    }

    /**
     * 刷新凭证有效期
     * @param token 凭证
     */
    public void refreshTokenExpires(String token) {
        cacheUserManager.refreshTokenExpires(token, tokenExpires);
    }

    /**
     * 获取凭证有效期
     * @param token 凭证
     * @return long
     */
    public long getTokenExpires(String token) {
        return cacheUserManager.getTokenExpires(token);
    }

    /**
     * 获取用户信息
     * @param token 凭证
     * @return Object
     */
    public Object getUser(String token) {
        return cacheUserManager.getUser(token);
    }

    /**
     * 凭证失效
     * @param token 凭证
     */
    public void invalidToken(String token) {
        cacheUserManager.invalidToken(token);
    }

    /**
     * 缓存session与token的关系
     * @param token 凭证
     * @param session SESSION
     */
    public void cacheSession(String token, String session) {
        if(StringUtils.isNotEmpty(session)) {
            cacheUserManager.cacheSession(token, session, tokenExpires);
        }
    }

    /**
     * 根据SESSION获取token
     * @param session SESSION
     * @return String
     */
    public String getTokenBySession(String session) {
        return StringUtils.isEmpty(session) ? null : cacheUserManager.getTokenBySession(session);
    }

    /**
     * 缓存认证授权码
     * @param code 授权码
     * @param client_id 关联的应用id
     * @param token 凭证
     */
    public void cacheCode(String code, String client_id, String token) {
        cacheUserManager.cacheCode(code, client_id, token);
    }

    /**
     * 使用授权码获取token
     * @param code 授权码
     * @param client_id 关联的应用id
     * @return String
     */
    public String getTokenByCode(String code, String client_id) {
        return cacheUserManager.getTokenByCode(code, client_id);
    }

    /**
     * 授权码失效
     * @param code 授权码
     * @param client_id 关联的应用id
     */
    public void invalidCode(String code, String client_id) {
        cacheUserManager.invalidCode(code, client_id);
    }

    public String getUserInterceptPath() {
        return userInterceptPath;
    }

    public AuthenticationManager setUserInterceptPath(String userInterceptPath) {
        this.userInterceptPath = userInterceptPath;
        return this;
    }

    public String getUserExcludePath() {
        return userExcludePath;
    }

    public AuthenticationManager setUserExcludePath(String userExcludePath) {
        this.userExcludePath = userExcludePath;
        return this;
    }

    public String getClientInterceptPath() {
        return clientInterceptPath;
    }

    public AuthenticationManager setClientInterceptPath(String clientInterceptPath) {
        this.clientInterceptPath = clientInterceptPath;
        return this;
    }

    public String getClientExcludePath() {
        return clientExcludePath;
    }

    public AuthenticationManager setClientExcludePath(String clientExcludePath) {
        this.clientExcludePath = clientExcludePath;
        return this;
    }

    public boolean isUserLoginDisable() {
        return userLoginDisable;
    }

    public AuthenticationManager setUserLoginDisable(boolean userLoginDisable) {
        this.userLoginDisable = userLoginDisable;
        return this;
    }

    public boolean isClientLoginDisable() {
        return clientLoginDisable;
    }

    public AuthenticationManager setClientLoginDisable(boolean clientLoginDisable) {
        this.clientLoginDisable = clientLoginDisable;
        return this;
    }

    public boolean isUserOnlineDisable() {
        return userOnlineDisable;
    }

    public AuthenticationManager setUserOnlineDisable(boolean userOnlineDisable) {
        this.userOnlineDisable = userOnlineDisable;
        return this;
    }

    public boolean isClientOnlineDisable() {
        return clientOnlineDisable;
    }

    public AuthenticationManager setClientOnlineDisable(boolean clientOnlineDisable) {
        this.clientOnlineDisable = clientOnlineDisable;
        return this;
    }
}
